<template>
  <el-row>
    <el-col :span="24">
      <div :class="{'search-bg': background}" v-show="state.showSearch" class="search">
        <x-resize @resize="onResize">
          <x-search @search="onSearch" ref="searchRef"></x-search>
        </x-resize>
      </div>
    </el-col>
    <el-col :span="24">
      <div :class="{'table-bg': background, 'table': background}">
        <div class="tool x-space-between x-mb-10">
          <div class="left">
            <slot name="btn-tool"></slot>
          </div>

<!--          <div class="right x-row-reverse">-->
<!--            <div class="x-pointer x-ml-10">-->
<!--              <el-popover-->
<!--                  placement="bottom-start"-->
<!--                  :width="120"-->
<!--                  trigger="hover">-->

<!--                <el-checkbox-group v-model="checkedColumns">-->
<!--                  <el-checkbox :label="col.field" v-for="(col, index) in columns">{{ col.title }}</el-checkbox>-->
<!--                </el-checkbox-group>-->

<!--                <template #reference>-->
<!--                  <el-icon size="16px">-->
<!--                    <Menu/>-->
<!--                  </el-icon>-->
<!--                </template>-->
<!--              </el-popover>-->

<!--            </div>-->
<!--            <div style="cursor: pointer">-->
<!--              <el-tooltip effect="light" content="刷新" placement="top-start">-->
<!--                <el-icon @click="onRefresh" size="16px">-->
<!--                  <RefreshLeft/>-->
<!--                </el-icon>-->
<!--              </el-tooltip>-->
<!--            </div>-->
<!--          </div>-->
        </div>

        <el-table
            v-show="! $emptyArray(columns)"
            stripe
            border
            style="width: 100%"
            ref="tableRef"
            v-bind="$attrs"
            id="el-table-mouse"
            :row-key="getRowKeys"
            highlight-current-row
            @row-click="onRowClick"
            @row-contextmenu="onRightClick"
            v-loading="state.loading"
            :data="tableData"
            @selection-change="onSelectionChange"
            @select="onSelect"
            :select-on-indeterminate="false"
            @sort-change="onSortChange"
            :height="offsetHeight == 'auto' ? 'auto' : mainHeight - searchFormHeight - offsetHeight"
            :tree-props="{children: 'children', hasChildren: 'hasChildren'}"
            :header-cell-style="{ background: '#F8F8F9', color: '#666' }">

          <slot>
            <el-table-column label="#" type="index" width="60" :index="indexMethod"></el-table-column>
            <el-table-column :selectable="selectable"  v-if="showCheckbox" type="selection" :reserve-selection="true" width="45"></el-table-column>
            <!-- 字段区域 -->
            <template v-for="(col, index) in columns">
              <el-table-column :key="index"
                               show-overflow-tooltip
                               v-platform
                               v-if="col.show"
                               :sortable="col.sort"
                               :align="col.align ? col.align : 'center'"
                               :prop="col.field" :label="col.title"
                               :width="col.width" :min-width="col.minWidth">
                <template #default="scope">
                  <slot :name="col.field" :data="scope.row">
                    {{ handleValue(scope.row, col) }}
                  </slot>
                </template>
              </el-table-column>
            </template>

            <!-- 操作区 -->
            <el-table-column align="center" v-if="! $emptyArray(options)" :fixed="fixed" label="操作"
                             :width="optionWidth + 'px'">
              <template #default="scope">
                <slot name="options" :data="scope.row">
                  <div class="x-center">
                    <template v-for="(op, index) in options">
                      <slot v-if="enabled(op, scope.row)" :name="op.emit" :data="scope.row">
                        <div v-if="$empty(op.img)" style="padding: 0 3px;box-sizing: border-box"
                             :style="{color: op.title == '删除' ? 'red' : '#2d82eb'}"
                             @click.stop="$emit(op.emit, scope.row)">
                          <span class="x-pointer">{{ op.title }}</span>
                        </div>
                        <div v-else @click.stop="$emit(op.emit, scope.row)" class="op x-center x-pointer">
                          <el-tooltip class="item" effect="dark" :content="op.title" placement="top-start">
                            <i :class="op.icon"></i>
                          </el-tooltip>
                        </div>

                        <el-dropdown v-if="! $emptyArray(op.children)" @command="$emit($event, scope.row)">
                          <div class="op x-center">
                            <span style="color: #2d82eb" class="x-pointer">{{ op.title ? op.title : "更多" }}</span>
                          </div>

                          <template #dropdown>
                            <el-dropdown-menu>
                              <template v-for="(child, index) in op.children">
                                <el-dropdown-item v-if="enabled(child, scope.row)" :command="child.emit" :key="index">
                                  {{ child.title }}
                                </el-dropdown-item>
                              </template>
                            </el-dropdown-menu>
                          </template>
                        </el-dropdown>
                      </slot>

                    </template>
                  </div>
                </slot>
              </template>
            </el-table-column>
          </slot>
        </el-table>
        <template v-if="isPage">
          <div class="x-row-reverse x-mt-10">
            <el-pagination
                :current-page="state.pageNo"
                :page-size="state.pageSize"
                :page-sizes="state.sizeList"
                layout="total, sizes, prev, pager, next, jumper"
                :total="state.total"
                @size-change="onPageSizeChange"
                @current-change="onPageChange"
            />
          </div>
        </template>
      </div>
    </el-col>
  </el-row>

</template>

<script setup name="x-table">
import {RefreshLeft, Menu} from '@element-plus/icons-vue'
import XSearch from './Search';

import {GlobalConfig} from 'core';
import {nextTick, onMounted} from "vue";

const config = GlobalConfig()
const {mainHeight} = storeToRefs(config);
let emit = defineEmits(['search', 'rowClick'])
let props = defineProps({
  data:{
    type: Array,
    default: () => {
      return []
    }
  },

  config:{
    type: Object,
    default: () => {
      return {
        showSearch: false,
        columns: [],
        options: [],
        searchForm: [],
      }
    }
  },

  optionWidth: {
    type: Number,
    default: 150
  },

  fixed: {
    type: [String, Boolean],
    default: 'right',
  },

  rowKey: {
    default: "id",
  },

  showCheckbox: {
    type: Boolean,
    default: false
  },

  field: {
    type: Array,
    default: () => {
      return [];
    }
  },

  isPage: {
    type: Boolean,
    default: true
  },

  offsetHeight:{
    type: Number,
    default: 150
  },

  selectable:{
    type: Function,
    default: () => {
      return true
    }
  },

  parentKey:{
    type: String,
    default: "parentId"
  },

  background:{
    type: Boolean,
    default: true
  }
})


const state = reactive({
  pageNo: 1,
  pageSize: 10,
  total: 0,
  sizeList: [10, 50, 100, 200],
  loading: false,
  showSearch: false,
  background: true
})

let tableData = ref([]);
let columns = ref([]);
let options = ref([]);
let searchRef = ref();
let checkedColumns = ref([]);
let selectRows = ref([]);
let sortColumn = ref({});
let searchFormHeight = ref(0);
let tableRef = ref();

onMounted(() => {
  clearSelectRow();
})

const onResize = (width, height) => {
  searchFormHeight.value = height;
}

let id = ref("");

const setId = (id) => {
  id.value = id;
}

/**
 * 设置列
 * @param columns
 */
const setColumns = (value) => {
  if (Helper.emptyArray(value)) {
    return;
  }
  columns.value = value;

  let checkedColumnsCache = Cache.get(id.value);
  if (!Helper.emptyArray(checkedColumnsCache)) {
    checkedColumns.value = checkedColumnsCache;
    return;
  }

  for (let i = 0; i < value.length; i++) {
    let item = value[i];
    item.show = item.field == 'serviceOrgName' ? Helper.isPlatform() : true;
    checkedColumns.value.push(item.field);
  }
}

/**
 * 设置列
 * @param columns
 */
const setSearchForm = (value) => {
  if (Helper.emptyArray(value)) {
    state.showSearch = false;
    return;
  }
  state.showSearch = true;
  searchRef.value.setForm(value);
}

/**
 * 设置操作区
 * @param ops
 */
const setOptions = (ops) => {
  options.value = [];
  if (Helper.emptyArray(ops)) {
    return;
  }
  options.value = ops;
}

/**
 * 是否loading
 * @param bol
 */
const isLoading = (bol) => {
  state.loading = bol;
}

/**
 * 设置数据
 * @param data
 */
const setData = (data) => {
  if (!Array.isArray(data)) {
    data = [];
  }
  tableData.value = data;
  selectRows.value = [];
}

/**
 * 获取数据
 * @returns {[]}
 */
const getData = () => {
  return tableData.value;
}

/**
 * 设置分页
 * @param pageNo 当前页
 * @param pageSize 每页大小
 * @param total 总数
 */
const setPagination = (pageNo = 1, pageSize = 10, total = 0) => {
  state.pageNo = pageNo;
  state.pageSize = pageSize;
  state.total = total;
}

/**
 * 获取每页大小
 * @returns {{total: number, pageNo: number, pageSize: number}}
 */
const getPagination = () => {
  return {pageNo: state.pageNo, pageSize: state.pageSize, total: state.total};
}

const clearSelectRow = () => {
  if(tableRef.value) {
    tableRef.value.clearSelection();
  }
}

/**
 * 返回选中行
 * */
const getSelectRows = () => {
  if (props.showCheckbox) {
    return selectRows.value;
  } else {
    return selectRows.value[0];
  }
}

/**
 * 获取id数组
 * @param list
 */
const setSelectRows = (list) => {
  if (! Array.isArray(list)) {
    selectRows.value = [];
  }
  selectRows.value = list;
  if (props.showCheckbox && ! Helper.emptyArray(selectRows.value)) {
    tableRef.value.clearSelection();
    toggleRowSelection(tableData.value, selectRows.value)
  }
}

/**
 * 处理值
 * */
const handleValue = (row, item) => {
  if (item.format) {
    return item.format(row[item.field], row);
  }
  return row[item.field];
}

/**
 * 重写索引
 * */
const indexMethod = (index) => {
  return (state.pageNo - 1) * state.pageSize + index + 1;
}


/**
 * 获取当前行主键
 * @param row
 * @returns {*}
 */
const getRowKeys = (row) => {
  let key = props.rowKey;
  if (!key) {
    key = 'id';
  }

  return row[key];
}

/**
 * 单击当行
 * */
const onRowClick = (row, column, e) => {
  if (props.showCheckbox) {
    selectRows.value.push(row);
    if (column.label != '操作') {
      row.xSeleced = !row.xSeleced;
      tableRef.value.toggleRowSelection(row, row.xSeleced);
    }
  } else {
    selectRows.value[0] = row;
  }
  emit('rowClick', row, column, e);
}

const toggleRowSelection = (rows, selectList) => {
  if(Helper.emptyArray(rows)) {
    return;
  }

  rows.forEach(row => {
    let key = getRowKeys(row);
    if(selectList.indexOf(key) > -1) {
      tableRef.value.toggleRowSelection(row, true);
    } else {
      tableRef.value.toggleRowSelection(row, false);
    }

    if(! Helper.emptyArray(row.children)) {
      toggleRowSelection(row.children, selectList);
    }
  })
}


/**
 * 复选框触发事件
 * */
const onSelectionChange = (selection) => {
  selectRows.value = selection;
}

const onSelect = (selection, row) => {
  let parentId = row[props.parentKey];
  if(! Helper.empty(parentId)) {
    let parent = findData(tableData.value, parentId);
    let selectList = [];
    if(! Helper.emptyArray(selection)) {
      selectList = selection.map((data,index,arr) => {
          return getRowKeys(data);
      })
    }
    if(parent != null) {
      tableRef.value.toggleRowSelection(parent, true);
      toggleRowSelection(parent.children, selectList);
    }
  }
}

/**
 * 右键菜单
 * */
const onRightClick = (row, column, e) => {
  console.log(row, column, e);
}

/**
 * 点击查询触发事件
 * @param formData
 */
const onSearch = (formData) => {
  state.pageNo = 1;
  search();
}

/**
 * 每页大小触发查询
 * */
const onPageSizeChange = (pageSize) => {
  state.pageSize = pageSize;
  search();
}

const onPageChange = (pageNo) => {
  state.pageNo = pageNo;
  search();
}

const onRefresh = () => {
  search();
}

const onSortChange = (row) => {
  if (!row.order) {
    sortColumn.value = {};
    return;
  }

  sortColumn.value = {field: row.prop, order: row.order == 'descending' ? 'desc' : 'asc'};
  search();
}

/**
 * 验证操作区按钮是否启用
 * @param op
 * @param row
 * @returns {boolean|*}
 */
const enabled = (op, row) => {
  if (op.check) {
    return op.check(row);
  }

  return true;
}

const search = () => {
  if (props.isPage) {
    emit('search', state.pageNo, state.pageSize, searchRef.value.getFormData(), sortColumn.value)
  } else {
    emit('search', searchRef.value.getFormData(), sortColumn.value)
  }
}

const findData = (dataList, id) => {
  if(Helper.emptyArray(dataList)) {
    return null;
  }

  for (let i=0;i<dataList.length; i++) {
    let data = dataList[i];
    let key = getRowKeys(data);
    if(id == key) {
      return data;
    }

    return findData(data.children, id);
  }
}

/**
 * 监听
 */
watch(() => checkedColumns.value, (value) => {
  for (let i = 0; i < columns.value.length; i++) {
    let item = columns.value[i];
    if (value.indexOf(item.field) > -1) {
      item.show = true;
    } else {
      item.show = false;
    }
  }
  if (!Helper.empty(id.value)) {
    Cache.set(id.value, value);
  }
})

watch(() => props.config, value => {
  state.showSearch = value.showSearch;
  setColumns(value.columns);
  setOptions(value.options);
  setSearchForm(value.searchForm);
}, {immediate: true})

watch(() => props.data, value => {
  nextTick(() => {
    setData(value);
  })
}, {immediate: true})

// watch(()=>props.field, (value) => setColumns(value),{immediate: true})
defineExpose({
  setId,
  setColumns,
  setSearchForm,
  setOptions,
  setData,
  getData,
  setPagination,
  getPagination,
  clearSelectRow,
  getSelectRows,
  setSelectRows,
  isLoading,
})
</script>

<style scoped lang="less">
.search {
  padding: 10px 16px 0 16px;
  box-sizing: border-box;
  margin-bottom: 10px;
}

.search-bg {
  background-color: #fff;
  border-radius: 4px;
  box-shadow: 0 4px 8px rgba(202, 216, 240, 0.6);
}

.table-bg {
  background-color: #fff;
  border-radius: 4px;
  box-shadow: 0 4px 8px rgba(202, 216, 240, 0.6);
}

.table {
  padding: 10px 16px 10px 16px;
  box-sizing: border-box;
}

.tool {
  width: 100%;
  //height: 32px;
}

.op {
  cursor: pointer;

  img {
    width: 22px;
    height: 22px;
  }
}
</style>
